package com.qudian.pay.core.diagnostic;

import java.text.MessageFormat;
import java.util.Collections;
import java.util.List;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.Lists;

/**
 * @Description: 性能统计-针对function的抽象类
 * @ClassName: Entry
*
 * @date 2016年5月17日 下午2:52:45
 */
public final class Entry {
	
	/**
	 * @Fields threshold : 判定是循环调用的阈值
	 */ 
	public final static Integer threshold = 4;
	
	/**
	 * @Fields subEntries : 子方法列表
	 */
	private final List<Entry> subEntries = Lists.newArrayList();
	
	private String message;
	
	/**
	 * @Fields parentEntry : 上级function
	 */
	private final Entry parentEntry;
	
	/**
	 * @Fields firstEntry : 第一个function
	 */
	private final Entry firstEntry;
	
	/**
	 * @Fields baseTime : 最初开始时间
	 */
	private final long baseTime;
	
	/**
	 * @Fields startTime : 进入本function开始时间
	 */
	private final long startTime;
	
	/**
	 * @Fields endTime : 执行完本function结束时间
	 */
	private long endTime;
	
	private boolean isStart = false;
	
	public final static String cycleAlert = "循环调用";
	
	public final static String cycleAlertMsg = cycleAlert + "【%s】共【%s】次";
	
	public Entry(String message, Entry parentEntry, Entry firstEntry) {
		this.message = message;
		this.startTime = System.currentTimeMillis();
		this.parentEntry = parentEntry;
		this.firstEntry = ObjectUtils.defaultIfNull(firstEntry, this);
		this.baseTime = (firstEntry == null) ? 0 : firstEntry.startTime;
		this.isStart = true;
	}
	
	public String getMessage() {
		return StringUtils.defaultIfEmpty(message, null);
	}
	
	public long getStartTime() {
		return (baseTime > 0) ? (startTime - baseTime) : 0;
	}
	
	/**
	 * @Description: 获得总执行时间
	 * @return long 返回类型
	*
	 * @date 2016年5月17日 下午2:56:19
	 */
	public long getEndTime() {
		if (endTime < baseTime) {
			return -1;
		} else {
			return endTime - baseTime;
		}
	}
	
	/**
	 * @Description: 本function执行时间
	 * @return long 返回类型
	*
	 * @date 2016年5月17日 下午2:56:50
	 */
	public long getDuration() {
		if (endTime < startTime) {
			return -1;
		} else {
			return endTime - startTime;
		}
	}
	
	public long getDurationOfSelf() {
		long duration = getDuration();
		if (duration < 0) {
			return -1;
		} else if (subEntries.isEmpty()) {
			return duration;
		} else {
			for (int i = 0; i < subEntries.size(); i++) {
				Entry subEntry = (Entry) subEntries.get(i);
				duration -= subEntry.getDuration();
			}
			if (duration < 0) {
				return -1;
			} else {
				return duration;
			}
		}
	}
	
	/**
	 * @Description: 获取本次运行时长 占上级百分比
	 * @return double 返回类型
	*
	 * @date 2016年5月17日 下午2:48:55
	 */
	public double getPecentage() {
		double parentDuration = 0;
		double duration = getDuration();
		if ((parentEntry != null) && parentEntry.isReleased()) {
			parentDuration = parentEntry.getDuration();
		}
		if ((duration > 0) && (parentDuration > 0)) {
			return duration / parentDuration;
		} else {
			return 0;
		}
	}
	
	/**
	 * @Description: 获取本次运行时长 占总时长百分比
	 * @return double 返回类型
	*
	 * @date 2016年5月17日 下午2:49:53
	 */
	public double getPecentageOfAll() {
		double firstDuration = 0;
		double duration = getDuration();
		if ((firstEntry != null) && firstEntry.isReleased()) {
			firstDuration = firstEntry.getDuration();
		}
		if ((duration > 0) && (firstDuration > 0)) {
			return duration / firstDuration;
		} else {
			return 0;
		}
	}
	
	/**
	 * @Description: 获取子运行入口
	 * @return List<Entry> 返回类型
	*
	 * @date 2016年5月17日 下午2:50:43
	 */
	public List<Entry> getSubEntries() {
		return Collections.unmodifiableList(subEntries);
	}
	
	/**
	 * @Description: 释放，获得结束时间
	 * @return void 返回类型
	*
	 * @date 2016年5月17日 下午2:51:02
	 */
	public void release() {
		endTime = System.currentTimeMillis();
	}
	
	/**
	 * @Description: 判断当前entry是否结束
	 * @return boolean 返回类型
	*
	 * @date 2016年5月17日 下午2:51:24
	 */
	public boolean isReleased() {
		return endTime > 0;
	}
	
	/**
	 * @Description: 进入子方法
	 * @param message
	 * @return void 返回类型
	*
	 * @date 2016年5月17日 下午2:51:51
	 */
	public void enterSubEntry(String message) {
		subEntries.add(new Entry(message, this, firstEntry));
	}
	
	public void enterSubEntry(String message, Integer times) {
		for (int i = 0; i < subEntries.size(); i++) {
			Entry subentry = subEntries.get(i);
			String format = String.format(Entry.cycleAlertMsg, message, times-1);
			if (StringUtils.equals(subentry.getMessage(), format)) {
				subentry.setMessage(String.format(Entry.cycleAlertMsg, message, times));
				subentry.endTime = 0L;
				return;
			} else if (times == threshold) {
				enterSubEntry(String.format(Entry.cycleAlertMsg, message, times));
				return;
			}
		}
	}
	
	/**
	 * @Description: 获得未释放方法
	 * @return Entry 返回类型
	*
	 * @date 2016年5月17日 下午2:52:18
	 */
	public Entry getUnreleasedEntry() {
		Entry subEntry = null;
		if (!subEntries.isEmpty()) {
			subEntry = subEntries.get(subEntries.size() - 1);
			if (subEntry.isReleased()) {
				subEntry = null;
			}
		}
		return subEntry;
	}
	
	public String toString(String prefix1, String prefix2) {
		StringBuffer buffer = new StringBuffer();
		toString(buffer, prefix1, prefix2);
		buffer.append('\n');
		return buffer.toString();
	}
	
	/**
	 * @Description: 性能日志
	 * @param buffer
	 * @param prefix1
	 * @param prefix2
	 * @return void 返回类型
	*
	 * @date 2016年5月17日 下午2:58:00
	 */
	private void toString(StringBuffer buffer, String prefix1, String prefix2) {
		buffer.append(prefix1);
		String message = getMessage();
		String entryMsg = null;
		// 循环处理
		if (StringUtils.startsWith(message, cycleAlert)) {
			entryMsg = message;
		} else {
			long duration = getDuration();
			long durationOfSelf = getDurationOfSelf();
			double percentOfAll = getPecentageOfAll();
			Object[] params = new Object[] {
					// entry信息
					message,
					// 起始时间
					new Long(getStartTime()),
					// 持续总时间
					new Long(duration),
					// 自身消耗的时间
					new Long(durationOfSelf),
					// 在总时间中所旧的时间比例
					new Double(percentOfAll) };
			StringBuffer pattern = new StringBuffer("{1,number} ");
			if (isReleased()) {
				pattern.append("[{2,number}ms");
				if ((durationOfSelf > 0) && (durationOfSelf != duration))
					pattern.append(" ({3,number}ms)");
				if (percentOfAll > 0)
					pattern.append(", {4,number,##%}");
				pattern.append("]");
			} else {
				pattern.append("[UNRELEASED]");
			}
			if (message != null)
				pattern.append(" - {0}");
			entryMsg = MessageFormat.format(pattern.toString(), params);
		}
		buffer.append(entryMsg);
		for (int i = 0; i < subEntries.size(); i++) {
			Entry subEntry = subEntries.get(i);
			buffer.append('\n');
			int lastIndex = subEntries.size() - 1;
			// 最后一项
			if (i == lastIndex) {
				subEntry.toString(buffer, prefix2 + "`---", prefix2 + "    ");
				// 中间项
			} else {
				subEntry.toString(buffer, prefix2 + "+---", prefix2 + "|   ");
			}
		}
	}
	
	public boolean isStart() {
		return isStart;
	}
	
	public void setMessage(String message) {
		this.message = message;
	}
	
	public Entry getParentEntry() {
		return parentEntry;
	}
}
